package com.ljw.gulimall.product.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ljw.common.constant.ProductConstant;
import com.ljw.common.to.SkuHasStockVo;
import com.ljw.common.to.SkuReductionTo;
import com.ljw.common.to.SpuBoundTo;
import com.ljw.common.to.es.SkuEsModel;
import com.ljw.common.to.ware.WareSkuTo;
import com.ljw.common.utils.R;
import com.ljw.gulimall.product.entity.*;
import com.ljw.gulimall.product.feign.CouponFeignService;
import com.ljw.gulimall.product.feign.SearchFeignService;
import com.ljw.gulimall.product.feign.WareFeignService;
import com.ljw.gulimall.product.service.*;
import com.ljw.gulimall.product.vo.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ljw.common.utils.PageUtils;
import com.ljw.common.utils.Query;

import com.ljw.gulimall.product.dao.SpuInfoDao;
import org.springframework.transaction.annotation.Transactional;


@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Autowired
    private SpuInfoDescService spuInfoDescService;

    @Autowired
    private SpuImagesService spuImagesService;

    @Autowired
    private ProductAttrValueService productAttrValueService;

    @Autowired
    private AttrService attrService;

    @Autowired
    private SkuInfoService skuInfoService;

    @Autowired
    private SkuImagesService skuImagesService;

    @Autowired
    private SkuSaleAttrValueService skuSaleAttrValueService;

    @Autowired
    private CouponFeignService couponFeignService;

    @Autowired
    private BrandService brandService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private WareFeignService wareFeignService;

    @Autowired
    private SearchFeignService searchFeignService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 保存发布商品的信息
     * @param vo
     */
    @Transactional
    @Override
    public void saveSpuInfo(SpuSaveVo vo) {

        //1、保存spu基本信息 pms_spu_info
        //数据映射
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        BeanUtils.copyProperties(vo, spuInfoEntity);
        //设置时间
        spuInfoEntity.setCreateTime(new Date());
        spuInfoEntity.setUpdateTime(new Date());
        //保存
        this.save(spuInfoEntity);

        //2、保存spu描述图片 pms_spu_info_desc
        List<String> decript = vo.getDecript();
        SpuInfoDescEntity spuInfoDescEntity = new SpuInfoDescEntity();
        spuInfoDescEntity.setSpuId(spuInfoEntity.getId());
        //把集合中的图片地址用逗号分隔开来保存
        spuInfoDescEntity.setDecript(String.join(",", decript));
        spuInfoDescService.save(spuInfoDescEntity);

        //3、保存spu的图片集 pms_spu_images
        List<String> images = vo.getImages();
        spuImagesService.saveImages(spuInfoEntity.getId(), images);

        //4、保存spu的规格参数 pms_product_attr_value
        //前端只传过来了属性的id，但pms属性表中需要保存属性的名字，所以要去属性表中查出各个属性得到其名字
        List<BaseAttrs> baseAttrs = vo.getBaseAttrs();
        //封装属性id批量查询出属性
        List<Long> attrIds = baseAttrs.stream().map(attr -> {
            return attr.getAttrId();
        }).collect(Collectors.toList());
        List<AttrEntity> attrEntities = (List<AttrEntity>) attrService.listByIds(attrIds);
        List<ProductAttrValueEntity> productAttrValueEntities = new ArrayList<>();
        //设置属性的名字
        for (int i = 0; i < baseAttrs.size(); i++) {
            for (int j = 0; j < attrEntities.size(); j++) {
                if (baseAttrs.get(i).getAttrId().equals(attrEntities.get(j).getAttrId())){
                    ProductAttrValueEntity productAttrValueEntity = new ProductAttrValueEntity();
                    productAttrValueEntity.setAttrValue(baseAttrs.get(i).getAttrValues());
                    productAttrValueEntity.setAttrId(baseAttrs.get(i).getAttrId());
                    productAttrValueEntity.setAttrName(attrEntities.get(j).getAttrName());
                    productAttrValueEntity.setQuickShow(baseAttrs.get(i).getShowDesc());
                    productAttrValueEntity.setSpuId(spuInfoEntity.getId());
                    productAttrValueEntities.add(productAttrValueEntity);
                    break;
                }
            }
        }
        //map映射表中的对应的实体类
        //批量保存
        productAttrValueService.saveBatch(productAttrValueEntities);

        //5、保存当前spu对应的所有sku信息
        //5.1、保存sku的基本信息 pms_sku_info
        List<Skus> skus = vo.getSkus();
        List<SkuInfoEntity> skuInfoEntities = skus.stream().map(skuInfo -> {
            SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
            // skuName, price, skuTitle, skuSubtitle直接copy过去
            BeanUtils.copyProperties(skuInfo, skuInfoEntity);
            // 设置不能copy的属性
            skuInfoEntity.setSpuId(spuInfoEntity.getId());
            skuInfoEntity.setBrandId(spuInfoEntity.getBrandId());
            skuInfoEntity.setCatalogId(spuInfoEntity.getCatalogId());
            skuInfoEntity.setSaleCount(0L);
            List<Images> skuImages = skuInfo.getImages();
            String skuDefaultImage = "";
            for (int i = 0; i < skuImages.size(); i++) {
                if (skuImages.get(i).getDefaultImg() == 1) {
                    skuDefaultImage = skuImages.get(i).getImgUrl();
                    break;
                }
            }
            skuInfoEntity.setSkuDefaultImg(skuDefaultImage);
            return skuInfoEntity;
        }).collect(Collectors.toList());
        skuInfoService.saveBatch(skuInfoEntities);


        List<SkuImagesEntity> skuImagesEntities = new ArrayList<>();
        List<SkuSaleAttrValueEntity> skuSaleAttrValueEntities = new ArrayList<>();
        List<SkuReductionTo> skuReductionTos = new ArrayList<>();
        List<WareSkuTo> wareSkuTos = new ArrayList<>();
        for (int i = 0; i < skus.size(); i++) {
            //5.2、保存sku的图片信息 pms_sku_images
            List<Images> skuImages = skus.get(i).getImages();
            for (Images skuImage : skuImages) {
                SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                skuImagesEntity.setSkuId(skuInfoEntities.get(i).getSkuId());
                skuImagesEntity.setImgUrl(skuImage.getImgUrl());
                skuImagesEntity.setDefaultImg(skuImage.getDefaultImg());
                skuImagesEntities.add(skuImagesEntity);
            }

            //5.3、保存sku的销售属性 pms_sku_sale_attr_value
            List<Attr> attr = skus.get(i).getAttr();
            for (Attr item : attr) {
                SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
                BeanUtils.copyProperties(item, skuSaleAttrValueEntity);
                skuSaleAttrValueEntity.setSkuId(skuInfoEntities.get(i).getSkuId());
                skuSaleAttrValueEntities.add(skuSaleAttrValueEntity);
            }

            //5.4、保存sku的优惠满减信息 gulimall_sms -> sms_spu_bounds\sms_sku_ladder\sms_sku_full_reduction\sms_member_price
            SkuReductionTo skuReductionTo = new SkuReductionTo();
            BeanUtils.copyProperties(skus.get(i), skuReductionTo);
            skuReductionTo.setSkuId(skuInfoEntities.get(i).getSkuId());
            skuReductionTos.add(skuReductionTo);

            //5.5、保存sku库存信息
            WareSkuTo wareSkuTo = new WareSkuTo();
            wareSkuTo.setSkuId(skuInfoEntities.get(i).getSkuId());
            wareSkuTo.setSkuName(skus.get(i).getSkuName());
            wareSkuTo.setWareId(1L);//默认设置1号仓库
            wareSkuTo.setStock(0); //默认每个sku的库存为0
            wareSkuTo.setStockLocked(0); //默认设置被锁住的库存为0
            wareSkuTos.add(wareSkuTo);

        }
        List<SkuImagesEntity> SkuImagesEntityFilter = skuImagesEntities.stream().filter(skuImagesEntity -> {
            return !StringUtils.isBlank(skuImagesEntity.getImgUrl());
        }).collect(Collectors.toList());
        skuImagesService.saveBatch(SkuImagesEntityFilter);
        skuSaleAttrValueService.saveBatch(skuSaleAttrValueEntities);
        couponFeignService.saveSkuReductionTos(skuReductionTos);
        wareFeignService.saveBatch(wareSkuTos);

        //5.4、保存spu的购买积分，成长积分信息，该表在coupon系统中
        Bounds bounds = vo.getBounds();
        SpuBoundTo spuBoundTo = new SpuBoundTo();
        BeanUtils.copyProperties(bounds, spuBoundTo);
        spuBoundTo.setSpuId(spuInfoEntity.getId());
        couponFeignService.saveBounds(spuBoundTo);


    }

    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        LambdaQueryWrapper<SpuInfoEntity> wrapper = new LambdaQueryWrapper<>();
        String key = (String) params.get("key");
        String status = (String) params.get("status");
        String brandId = (String) params.get("brandId");
        String catelogId = (String) params.get("catelogId");
        if (!StringUtils.isBlank(key)){
            wrapper.and( w -> {
                w.eq(SpuInfoEntity::getId, key).or().like(SpuInfoEntity::getSpuName, key);
            });
        }
        if (!StringUtils.isBlank(status)){
            wrapper.eq(SpuInfoEntity::getPublishStatus, status);
        }
        if (!StringUtils.isBlank(brandId) && !"0".equalsIgnoreCase(brandId)){
            wrapper.eq(SpuInfoEntity::getBrandId, brandId);
        }
        if (!StringUtils.isBlank(catelogId) && !"0".equalsIgnoreCase(catelogId)){
            wrapper.eq(SpuInfoEntity::getCatalogId, catelogId);
        }
        IPage<SpuInfoEntity> page = new Query<SpuInfoEntity>().getPage(params);
        baseMapper.selectPage(page, wrapper);
        return new PageUtils(page);
    }

    /**
     * 商品上架
     * @param spuId
     */
    @Override
    public void up(Long spuId) {
        List<SkuEsModel> upProducts = new ArrayList<>();

        //组装需要的数据
        //1、查出当前spu对应的sku信息，品牌的名字
        List<SkuInfoEntity> skus = skuInfoService.getSkuBySpuId(spuId);
        List<Long> skuIds = skus.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());

        //4、查询当前sku的所有可以用来被检索的规格属性
        List<ProductAttrValueEntity> productAttrValueEntities = productAttrValueService.baseAttrlistforspu(spuId);
        List<Long> attrIds = productAttrValueEntities.stream().map(productAttrValueEntity -> {
            return productAttrValueEntity.getAttrId();
        }).collect(Collectors.toList());
        List<Long> searchAttrIds = attrService.selectSearchAttrsIds(attrIds);
        Set<Long> idSet = new HashSet<>(searchAttrIds);
        List<SkuEsModel.Attrs> attrsList = productAttrValueEntities.stream().filter(productAttrValueEntity -> {
            return idSet.contains(productAttrValueEntity.getAttrId());
        }).map(productAttrValueEntity -> {
            SkuEsModel.Attrs attrs = new SkuEsModel.Attrs();
            attrs.setAttrId(productAttrValueEntity.getAttrId());
            attrs.setAttrName(productAttrValueEntity.getAttrName());
            attrs.setAttrValue(productAttrValueEntity.getAttrValue());
            return attrs;
        }).collect(Collectors.toList());

        //TODO 1、发送远程调用，查询库存系统中是否有库存
        Map<Long, Boolean> stockMap = null;
        try {
            R skuHasStock = wareFeignService.getSkuHasStock(skuIds);
            Object data = skuHasStock.get("data");
            String string = JSON.toJSONString(data);
            List<SkuHasStockVo> skuHasStockVos = JSON.parseArray(string,SkuHasStockVo.class);
            stockMap = skuHasStockVos.stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, SkuHasStockVo::getHasStock));
        }catch (Exception e){
            log.error("库存服务查询异常：原因{}",e);
        }


        Map<Long, Boolean> finalStockMap = stockMap;
        List<SkuEsModel> skuEsModelList = skus.stream().map(skuInfoEntity -> {
            SkuEsModel skuEsModel = new SkuEsModel();
            BeanUtils.copyProperties(skuInfoEntity, skuEsModel);
            /**
             * 需要单独处理的数据：skuPrice,skuImg,hasStock,hotScore,brandName,brandImg,catalogName,
             * Attrs类中的attrId,attrName,attrValue
             */
            skuEsModel.setSkuPrice(skuInfoEntity.getPrice());
            skuEsModel.setSkuImg(skuInfoEntity.getSkuDefaultImg());
            //TODO 1、发送远程调用，查询库存系统中是否有库存
            if (finalStockMap == null){
                skuEsModel.setHasStock(true);
            }
            else {
                skuEsModel.setHasStock(finalStockMap.get(skuInfoEntity.getSkuId()));
            }
            //TODO 2、热度评分。0
            //TODO 3、查询品牌和分类的名字信息
            BrandEntity brandEntity = brandService.getById(skuInfoEntity.getBrandId());
            skuEsModel.setBrandName(brandEntity.getName());
            skuEsModel.setBrandImg(brandEntity.getLogo());
            CategoryEntity categoryEntity = categoryService.getById(skuInfoEntity.getCatalogId());
            skuEsModel.setCatalogName(categoryEntity.getName());
            //TODO 4、查询当前sku的所有可以用来被检索的规格属性
            skuEsModel.setAttrs(attrsList);
            return skuEsModel;
        }).collect(Collectors.toList());

        //TODO 5、将数据发送给es进行保存 gulimall-search

        R r = searchFeignService.productStatusUp(skuEsModelList);
        Integer code = (Integer) r.get("code");
        if (code == 0){
            //远程调用成功，修改spu的状态码
            SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
            spuInfoEntity.setId(spuId);
            spuInfoEntity.setUpdateTime(new Date());
            spuInfoEntity.setPublishStatus(ProductConstant.StatusEnum.SPU_UP.getCode());
            baseMapper.updateById(spuInfoEntity);
        }
        else {
            //远程调用失败
            //TODO 7、重复调用？接口幂等性；重试机制？XXX
        }
    }

    @Override
    public SpuInfoEntity getSpuInfoBySkuId(Long skuId) {
        SkuInfoEntity byId = skuInfoService.getById(skuId);
        Long spuId = byId.getSpuId();
        SpuInfoEntity spuInfoEntity = this.getById(spuId);
        return spuInfoEntity;
    }

}